﻿//#include <stdio.h>
//#include <stdlib.h>
//C++的关键字：namespace:避免变量与（库）函数一样的命名
//经过封装后，内部的变量不会和库中的函数名混淆了
//命名空间域

//把函数，结构体，变量....封装到一个命名空间（类似结构体）里

//多个文件内可以定义同名的命名空间，同一个命名空间，同名命名空间会进行合并
//命名空间还可以嵌套（可以避免命名空间的重命名问题）
/*
namespace bit {
	namespace fz
	{
		int rand = 0;

		//除了变量，还可以定义函数和（结构体...）类型
		int Add(int left, int right)
		{
			return left + right;
		}

		struct Node
		{
			struct Node* next;
			int val;
		};

		int y=18;
	}
	int x = 0;
}

namespace fz
{
	int rand = 0;
	int Add(int left, int right)
	{
		return (left + right) * 10;
	}
}

using bit::fz::y;
using bit::x;

int main()
{
	printf("%p\n", rand);//这里是将库函数的rand地址打出来
	//如果想要打印封装过的自定义rand，如何
	//把namespace内部的rand看作一个全局变量，main函数（局部域）想要得到全局域的值：
	//在要访问的变量前加::域作用限定符）
	//域名::变量
	//没有域名就是访问全局
	//编译时默认查找顺序：1，当前局部域2，全局域 （不会到命名空间去找）
	//3.展开命名空间中65
	//加上 域名::变量 才能直接找到
	//printf("%d\n", bit::rand);

	printf("hello world\n");

	printf("%d\n", bit::fz::Add(1,2));//嵌套
	printf("%d\n", y);


	return 0;
}
*/
/*
//有时调用命名空间的次数过于频繁，要写很多个::，节省时间的方法：
//展开命名空间
using namespace fz;//让所有想使用的人，都可以使用
// 原本：fz::Add(1,2);，展开命名空间后：Add(1,2);不加fz::(指定的域）都可以用
//展开后出现的问题：又导致重命名
*/

//如果在使用命名空间时，经常使用某一个（成员），每次都要::很麻烦，
//新的引用方式：
//指定展开某一个
//using bit::x;
//using bit::fz::y;

//域：
// 局部域，全局域（会影响生命周期），命名空间域（不会影响生命周期）
//不同的域可以定义同名的变量/函数/类型


#include<iostream>//stdio.h的进化版

using namespace std;//多次使用避免繁琐：展开
//缺点：可能重名：指定展开
using std::cout;
using std::endl;

/*
int main()
{
	// << 流插入
	int i = 0;
	double j = 1.11;
	//console:控制台(终端)
	//下面语句的意思是讲插入的数据都流向控制台
	//endl的意思：换行

	// << 可以自动识别类型

	//注意：cout和endl都是iostream内部定义的，虽然include包含了，但是仍然无法使用
	//因为系统默认只在局部全局找，局部没有，全局也没有，只有引入的iostream内部域中有
	//所以需要给出域名::才能引用：std::  此库官方的命名空间域
	//std::cout << i << "" << j<<'\n'<<std::endl;

	//如果需要多次使用：便捷的方式：1，域展开
	//无需再加std:: 
	cout << i << " " << j << '\n' << endl;

	//>>流提取
	//把输入的i提取放到j里面（改变原来的值）
	std::cin >> i >> j;
	//scanf("%d%lf", &i, &j);
	cout << i << " " << j << '\n' << endl;
		return 0;
}
*/

//
//缺省参数
//缺省参数不能声明和定义同时给值
//缺省参数只在声明的位置给出（头文件内）
//缺省参数是声明或定义是为函数参数指定的一个缺省值。在调用该函数时，如果没有指定实参，则采用这个缺省值作为函数参数。否则使用指定形参。

//声明和定义不能同时给缺省值，会产生调用歧义
//缺省值必须是全局变量或者常量




/*


void F1(int a = 1)
{
	cout << a << endl;
}
//全缺省
void F2(int a = 10, int b = 20, int c = 30)
{
	cout << "a=" << a << endl;
	cout << "b=" << b << endl;
	cout << "c=" << c << endl<<endl;

}
//半缺省：！只能左边缺省（也不能跳跃缺省）
//因为赋值的时候是从左往右，定义参数的时候就只能省左边
//用于有自己想改变的值的情况，灵活性更高
void F3(int a , int b = 20, int c = 30)
{
	cout << "a=" << a << endl;
	cout << "b=" << b << endl;
	cout << "c=" << c << endl << endl;

}

int main()
{
	F2(1, 2, 3);
	F2(1, 2);
	F2(1);
	F2();

	//必须顺序地传，不能跳跃传
	//F2(1, , 2);//❌

	F2(1);
	F2(1, 2);
	F2(1, 2, 3);



		return 0;
}
*/


//函数重载：允许同名函数存在
//在同一作用域(全局/命名空间)，函数名相同：形参(类型)不同（个数/类型/顺序不同）
/*
namespace bit1
{
	void Swap(int* pa, int* pb)
	{
		cout << "void Swap(int* pa, int* pb)" << endl;
	}
}

namespace bit2
{
	void Swap(int* pa, int* pb)
	{
		cout << "void Swap(double* pa, double* pb)" << endl;
	}
}

void Swap(double* pa, double* pb)
{
	cout << "void Swap(double* pa, double* pb)" << endl;
}
//207/212构成重载：参数不同，与缺省参数没有关系
//但是用f();调用会存在歧义，调用时都不放入参数，有歧义
int f()
{
	cout << "f()" << endl;
}

void f(int a = 10)
{
	cout << "f(int a)" << endl;
}
//展开域
//using namespace bit1;
using namespace bit2;
//展开后，原本相同类型不同域的函数，就不构成重载了（相当于同一域内定义了相同的函数）

//函数重载是不看返回值的：只看参数是否重载（函数调用时：可以接收返回值也可以不接收，但是参数必须传递）
//f();
//int ret = f();
//返回值不是重载的条件

int main()
{
	int a = 0, b = 1;
	double c = 0.1,d = 1.1;

	Swap(&a, &b);//
	Swap(&c, &d);

	//f();//歧义
	f(1);

	return 0;
}
*/
//本质：形参类型的不同

//为什么c++支持重载？C不支持？（面试题）
//函数名修饰规则：公共函数+函数名

//引用：
/*
int main()
{
	int a = 0;
	//引用：取别名：b是a的别名
	int& b = a;
	//可以起多个别名
	int& c = a;
	//还可以给别名取别名
	int& d = c;
	++d;//对其中一个++其他都++：类似于取地址来++
	//在定义的时候就是引用，在其他地方就是取地址

	cout << &a << endl;
	cout << &b << endl;
	cout << &c << endl;
	cout << &d << endl;


		return 0;
}
*/

//
/*
void Swap(int& a, int& b)//此时：ab分别是xy的别名
{
	int tmp = a;
	a = b;
	b = tmp;
}



int main()
{
	int x = 0, y = 1;

	Swap(x, y);//要传地址&x
	//直接在传参的时候，将函数的参数类型名后加上&，取别名
	//可以达到通过别名改变实值的效果，（类似传地址来改变实参）
	cout << x << ":" << y << endl;

	int* p1 = &x;
	//还可以给指针变量取别名
	int*& pr = p1;

	pr = NULL;//对pr置空==p1置空

	return 0;
}
*/
//引用特性：
//引用在定义的时候，必须初始化（说清楚是谁的别名）
//一旦引用一个实体，不能再引用其他实体（只能是一个实体的别名）
//&&也是引用：诱值引用

//const int m = 0;//这时m是只读的
//int& n = m;
//报错：权限被放大，n是可读可写
//正确方式：const int& n = m;
// 
//权限的平移/缩小:是可以的
//
// 只是赋值(拷贝值给p，修改p不会影响m)，不是取别名，是可以的:
// const int& n = m;
// int p = m;


//编译默认查找：
//1，当前局部域
// 2，全局域/展开的命名空间（同名不指定会冲突）

//
//

#include<time.h>
struct A { int a[10000];};

void TestFunc1(A a){}//拷贝构造函数
void TestFunc2(A& a){}

void TestRefAndValue()
{
	A a;
	//以值作为参数传参
	size_t begin1 = clock();
	for (size_t i = 0; i < 10000; i++)
		TestFunc1(a);
	size_t end1 = clock();

	//以引用（别名）作为函数参数
	size_t begin2 = clock();
	for (size_t i = 0; i < 10000; i++)
		TestFunc2(a);
	size_t end2 = clock();

	//分别计算两个函数运行结束的时间
	cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;
	cout << "TestFunc2(A)-time:" << end2 - begin2 << endl;
}

//int main()
//{
//	TestRefAndValue();
//
//	return 0;
//}


//int main()
//{
//	//权限可以平移/缩小，不能放大
//	double d = 12.34;
//	//类型转换：会产生临时变量，再给目的数据赋值
//
//	int i = d;//可性
//
//	//int& r = d;//d先给了一个临时变量，临时变量具有常性==（被const修饰过）
//	//这样做相当于把r从const里面放出来了：导致权限的放大
//
//	const int& r = d;
//
//	int x = 0, y = 1;
//	const int& r2 = x + y;//如果不用值去接收：也是会产生临时变量的，
//	//也不能用放大的权限的值来接收
//
//	return 0;
//}

//类型转换/表达式运算：都会产生临时变量



//引用和指针的不同点：
//引用只是一个别名，语法上：不会新开空间，指针会开辟空间/汇编上：都是指针
//引用可以不初始化
//引用在初始化时引用一个实体后，不能引用其他实体，但指针可以在任何时候指向任何一个同类型实体
//没有NULL引用，但有NULL指针
//sizeof中的含义不同：引用：结果：引用的类型大小，指针：地址空间所占字节个数（32位四个字节）
//引用自加即实体+1，指针则是指针向后偏移一个类型的大小
//有多级指针，但没有多级引用
//访问实体方式不同，指针要解引用，引用：编译器自己处理
//引用比指针使用起来更加安全

//int main()
//{
//	int a = 0;
//	int& b = a;
//	int* p = &a;
//
//	int* ptr = NULL;
//	int& r = *ptr;//不报错
//	//本质：上面并没有对ptr进行解引用
//	// （引用只是取别名，编译上：只是用了一个指针将ptr这个空指针存起来了：而存一个空指针是没有错误的），不存在对空指针解引用的问题
//	//输出时会解引用
//	//
//	cout<<r<<endl;//报错
//
//	return 0;
//}


//如果有小的函数经常使用：每次调用都建立栈帧

//Debug版本下默认不展开->方便调试

//内联函数：不用建立栈帧
//
//inline int Add(int a, int b)
//{
//	int ret = a + b;
//	return a + b;
//}
//
////频繁调用的小函数，每次调用都要建立栈帧空间：
////解决问题：C语言：宏定义函数（容易出错）
//
//int main()
//{
//	int c = Add(1, 2);
//	cout << c << endl;
//
//	return 0;
//}
//内联函数缺点：
//  可能会使目标文件变大，展开指令增多
// （只是对编译器的一个建议）只适合小的函数调用，大的函数多次频繁调用不合适
//  较长/递归的函数不会展开


#include "F.h"
int main()
{
	f(10);

	return 0;
}




